
#include <stdio.h>

#include "olisp.h"

#define UNIT_TESTS_FOLDER "../../unit_tests/"

void test_reader1()
{
    const char * filename = UNIT_TESTS_FOLDER "test02.lsp";
    obj_t * e;
    reader_context ctx = { 0 };
    printer_context prn_ctx = { 0 };

    ctx.stream = fopen( filename, "rb" );
    ctx.err_handler = &dump_error_handler;

    if( !ctx.stream )
    {
        printf( "can't open %s\n", filename );
        return;
    }

    prn_ctx.stream = stderr;

    // read each element from stream
    for( ;; )
    {
        e = read_elem( &ctx );
        if( e )
        {
            print_elem( e, &prn_ctx );
            printf( "\n" );
            RELEASE( e );
        }
        else
        {
            printf( "END reading\n" );
            break;
        }
    }

    fclose( ctx.stream );
}

void test_reader2()
{
    //const char * src_string = "() (()) (hgfh kj () (lkj (jhbn kk  l  )))";
    const char *    src_string = "(hgfh 123 sdf? (nil kljh   t ))";
    FILE *          ftemp_stream = fopen( "c:\\temp", "wD" );
    obj_t *   e;
    reader_context  rdr_ctx = { 0 };
    printer_context prn_ctx = { 0 };


    rdr_ctx.err_handler = &dump_error_handler;
    rdr_ctx.stream = ftemp_stream;

    prn_ctx.stream = stderr;
    prn_ctx.options = PRN_OPT_ADD_TYPEINFO;

    if( ftemp_stream )
    {
        fwrite( src_string, 1, strlen(src_string), ftemp_stream );
        fseek( ftemp_stream, 0, SEEK_SET );

        for( ;; )
        {
            e = read_elem( &rdr_ctx );
            if( e )
            {
                print_elem( e, &prn_ctx );
                printf( "\n" );
                RELEASE( e );
            }
            else
            {
                printf( "END reading\n" );
                break;
            }
        }

        fclose( ftemp_stream );
    }
    else
        printf( "can't open file\n" );
}

void test_reader3()
{
    reader_context ctx = { 0 };
    printer_context prn_ctx = { 0 };

    ctx.err_handler = &dump_error_handler;
    ctx.stream = stdin;

    prn_ctx.stream = stderr;
    prn_ctx.options = PRN_OPT_ADD_TYPEINFO;
    for( ;; )
    {
        obj_t * e;

        printf( ">" );
        e = read_elem( &ctx );
        if( e )
        {
            print_elem( e, &prn_ctx );
            printf( "\n" );

            if( !lisp_strcmp(e, "quit") )
            {
                RELEASE( e );
                break;
            }

            RELEASE( e );
        }
        else
        {
            break;
        }
    }

    printf( "END reading\n" );
}

void test_quote_mgr()
{
    lisp_quote_mgr_t * quote_mgr = 0;
    const char * filename = UNIT_TESTS_FOLDER "test01.lsp";
    obj_t * e;
    reader_context rdr_ctx = { 0 };
    printer_context prn_ctx = { 0 };

    rdr_ctx.stream = fopen( filename, "rb" );
    if( !rdr_ctx.stream )
    {
        printf( "can't open %s\n", filename );
        goto LEnd;
    }

    quote_mgr = create_quote_mgr();
    if( !quote_mgr )
        goto LEnd;

    rdr_ctx.err_handler = &dump_error_handler;
    rdr_ctx.quote_mgr = quote_mgr;

    prn_ctx.quote_mgr = quote_mgr;
    prn_ctx.stream = stderr;

    // read each element from stream
    for( ;; )
    {
        e = read_elem( &rdr_ctx );
        if( e )
        {
            print_elem( e, &prn_ctx );
            printf( "\n" );
            RELEASE( e );
        }
        else
        {
            printf( "END reading\n" );
            break;
        }
    }

LEnd:
    if( rdr_ctx.stream )
        fclose( rdr_ctx.stream );
    if( quote_mgr )
        quote_mgr_dispose( quote_mgr );
}

void test_entity_process_decl_lang()
{
    const char * filename = UNIT_TESTS_FOLDER "test01.lsp";
    obj_t * e;
    reader_context rdr_ctx = { 0 };
    printer_context prn_ctx = { 0 };

    //ctx.quote_mgr = (lisp_quote_mgr_t *)&simple_quote_mgr;
    rdr_ctx.stream = fopen( filename, "rb" );
    if( !rdr_ctx.stream )
    {
        printf( "can't open %s\n", filename );
        return;
    }

    rdr_ctx.err_handler = &dump_error_handler;
    prn_ctx.stream = stderr;

    // read each element from stream
    for( ;; )
    {
        e = read_elem( &rdr_ctx );
        if( e )
        {
            print_elem( e, &prn_ctx );
            printf( "\n" );
            RELEASE( e );
        }
        else
        {
            printf( "END reading\n" );
            break;
        }
    }

    if( rdr_ctx.stream )
        fclose( rdr_ctx.stream );
}

void test_interpreter()
{
    const char * filename = UNIT_TESTS_FOLDER "test01.lsp";
    obj_t * e;
    reader_context rdr_ctx = { 0 };
    printer_context prn_ctx = { 0 };
    interpreter_context ir_ctx = { 0 };
    interpreter_t * interpreter = 0;

    // quote mgr
    lisp_quote_mgr_t * quote_mgr = 0;
    quote_mgr = create_quote_mgr();
    if( !quote_mgr )
        goto LEnd;

    ir_ctx.quote_mgr = rdr_ctx.quote_mgr = prn_ctx.quote_mgr = quote_mgr;

    rdr_ctx.stream = fopen( filename, "rb" );
    if( !rdr_ctx.stream )
    {
        printf( "can't open %s\n", filename );
        goto LEnd;
    }

    rdr_ctx.err_handler = &dump_error_handler;
    prn_ctx.stream = stderr;
    ir_ctx.err_stream = stderr;

    // create interpreter
    interpreter = create_interpreter( &ir_ctx );
    if( !interpreter )
        goto LEnd;

    // register lisp funcs
    if( !register_lf_arith(interpreter) )
    {
        printf( "can't register lf_arith" );
        goto LEnd;
    }

    // read each element from stream and interpret it
    for( ;; )
    {
        e = read_elem( &rdr_ctx );
        if( e )
        {
            obj_t * interpreted = interpreter_interpret( interpreter, e );
            if( interpreted )
            {
                print_elem( e, &prn_ctx );
                printf( " -> " );
                print_elem( interpreted, &prn_ctx );
                printf( "\n" );

                RELEASE( interpreted );
            }

            RELEASE( e );
        }
        else
        {
            printf( "END reading\n" );
            break;
        }
    }

LEnd:
    if( rdr_ctx.stream )
        fclose( rdr_ctx.stream );

    if( interpreter )
        interpreter_dispose( interpreter );

    if( quote_mgr )
        quote_mgr_dispose( quote_mgr );
}


void test()
{
    //test_reader1();
    test_interpreter();
    //test_reader3();

    //test_entity_process_decl_lang();
    //test_quote_mgr();
    //test_interpreter();
}

int main( int argc, char * argv[] )
{
    printf( "olisp test01\n" );

    test();

    lisp_dump_mem_leaks();

    getchar();
    return 0;
}
